﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Minestorm.Retro.Entities;
using Microsoft.Xna.Framework;

namespace Minestorm.Retro.GameLogic
{
    public class EntityManager
    {
        private EntityArray<Bullet> _bullets;
        private EntityArray<Mine> _mines;
        private Ship _ship;
        private Dropship _dropship;
        private MineLayer _mineLayer;
        private EntityArray<Star> _stars;
        private EntityArray<Fireball> _fireballs;
        private EntityArray<Explosion> _explosions;
        private EntityArray<PointSprite> _pointSprites;

        private GameTime _gameTime;

        public EntityManager()
        {
            _bullets = new EntityArray<Bullet>(30, 10);
            _mines = new EntityArray<Mine>(28, 2);
            _stars = new EntityArray<Star>(28, 2);
            _fireballs = new EntityArray<Fireball>(8, 2);
            _explosions = new EntityArray<Explosion>(8, 2);
            _pointSprites = new EntityArray<PointSprite>(50, 5);
        }

        public void Clear()
        {
            _ship = null;
            _dropship = null;
            _bullets.Clear();
            _mines.Clear();
            _stars.Clear();
            _fireballs.Clear();
            _explosions.Clear();
            _pointSprites.Clear();
        }

        public void Update(GameTime gameTime)
        {
            _gameTime = gameTime;
        }

        public IEnumerable<Entity> GetAllEntities()
        {
            if (_dropship != null && _dropship.ShouldDraw)
                yield return _dropship;

            foreach (var entity in _stars)
                if (entity != null && entity.ShouldDraw)
                    yield return entity;

            if (_ship != null && _ship.ShouldDraw)
                yield return _ship;

            foreach (var entity in _mines)
                if (entity != null && entity.ShouldDraw)
                    yield return entity;

            foreach (var entity in _fireballs)
                if (entity != null && entity.ShouldDraw)
                    yield return entity;

            foreach (var entity in _bullets)
                if (entity != null && entity.ShouldDraw)
                    yield return entity;

            foreach (var entity in _explosions)
                if (entity != null && entity.ShouldDraw)
                    yield return entity;

            if (_mineLayer != null && _mineLayer.ShouldDraw)
                yield return _mineLayer;
        }

        public void AddEntity(Entity entity)
        {
            entity.BornOn = _gameTime.TotalGameTime;

            entity.Initialize();

            if (entity is Dropship)
            {
                _dropship = (Dropship)entity;
                return;
            }

            if (entity is Ship)
            {
                _ship = (Ship)entity;
                return;
            }

            if (entity is Bullet)
            {
                _bullets.Add((Bullet)entity);
                return;
            }

            if (entity is Mine)
            {
                _mines.Add((Mine)entity);
                return;
            }

            if (entity is Star)
            {
                _stars.Add((Star)entity);
                return;
            }

            if (entity is Fireball)
            {
                _fireballs.Add((Fireball)entity);
                return;
            }

            if (entity is Explosion)
            {
                _explosions.Add((Explosion)entity);
                return;
            }

            if (entity is MineLayer)
            {
                _mineLayer = (MineLayer)entity;
                return;
            }

            if (entity is PointSprite)
            {
                _pointSprites.Add((PointSprite)entity);
                return;
            }
        }

        public Ship GetShip()
        {
            return _ship;
        }

        public MineLayer GetMineLayer()
        {
            return _mineLayer;
        }

        public Star GetStar(int index)
        {
            return _stars.GetElementAt(index);
        }

        public Star GetStar(Func<Star, bool> expr)
        {
            return _stars.Where(s => s.ShouldDraw).FirstOrDefault(expr);
        }

        public Mine[] GetMines()
        {
            return _mines.ToArray();
        }

        public Fireball[] GetFireballs()
        {
            return _fireballs.ToArray();
        }

        public Explosion[] GetExplosions()
        {
            return _explosions.ToArray();
        }

        public Bullet[] GetBullets()
        {
            return _bullets.ToArray();
        }

        public PointSprite[] GetPointSprites()
        {
            return _pointSprites.ToArray();
        }

        public Dropship GetDropship()
        {
            return _dropship;
        }

        public bool HasDropship()
        {
            return _dropship != null && _dropship.ShouldDraw;
        }

        public Star[] GetStars()
        {
            return _stars.ToArray();
        }
    }
}
